package com.ruifu.act.contorller;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

/**
 * 提供给Modeler流程编辑器内部服务使用
 *
 * @author lcq
 */
@RestController
@RequestMapping(value = "/service")
@Slf4j
public class ModelerController {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 保存/更新流程模版
     *
     * @param modelId
     * @param name
     * @param json_xml
     * @param svg_xml
     * @param description
     */
    @PutMapping(value = "/model/{modelId}/save")
    public void saveModel(@PathVariable String modelId,
                          @RequestParam("name") String name,
                          @RequestParam("json_xml") String json_xml,
                          @RequestParam("svg_xml") String svg_xml,
                          @RequestParam("description") String description) {
        try (InputStream svgStream = new ByteArrayInputStream(svg_xml.getBytes(StandardCharsets.UTF_8));
             ByteArrayOutputStream outStream = new ByteArrayOutputStream()) {
            Model model = repositoryService.getModel(modelId);

            ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());

            modelJson.put(ModelDataJsonConstants.MODEL_NAME, name);
            modelJson.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
            modelJson.put(ModelDataJsonConstants.MODEL_REVISION, model.getVersion() + 1);

            model.setMetaInfo(modelJson.toString());
            model.setName(name);
            model.setVersion(model.getVersion() + 1); //升版
            repositoryService.saveModel(model);

            byte[] bytes = json_xml.getBytes(StandardCharsets.UTF_8);
            JsonNode jsonNode = new ObjectMapper().readTree(bytes);

            //1.将要部署的流程process-id(def-key)与流程模板key进行绑定
            String processId = (jsonNode.findValue("properties").findValue("process_id")).textValue();
            if (StringUtils.isEmpty(processId) || !model.getKey().equals(processId)) {
                processId = model.getKey();
                ((ObjectNode) (jsonNode.get("properties"))).put("process_id", processId);
            }

            //2.如果流程图的name为空，则将其值置成当前model填写的name
            String processName = (jsonNode.findValue("properties").findValue("name")).textValue();
            if (StringUtils.isEmpty(processName)) {
                ((ObjectNode) (jsonNode.get("properties"))).put("name", name);
            }
            //3.如果流程图的documentation为空，则将其值置成当前model填写的description
            String documentation = (jsonNode.findValue("properties").findValue("documentation")).textValue();
            if (StringUtils.isEmpty(documentation)) {
                ((ObjectNode) (jsonNode.get("properties"))).put("documentation", description);
            }

            //同步更新xml流程的版本
            ((ObjectNode) (jsonNode.get("properties"))).put("process_version", model.getVersion());

            repositoryService.addModelEditorSource(model.getId(), jsonNode.toString().getBytes(StandardCharsets.UTF_8));

            TranscoderInput input = new TranscoderInput(svgStream);
            PNGTranscoder transcoder = new PNGTranscoder();
            // Setup output

            TranscoderOutput output = new TranscoderOutput(outStream);

            // Do the transformation
            transcoder.transcode(input, output);
            final byte[] result = outStream.toByteArray();
            repositoryService.addModelEditorSourceExtra(model.getId(), result);
        } catch (Exception e) {
            log.error("Error saving model", e);
            throw new ActivitiException("Error saving model", e);
        }
    }


    /**
     * 加载模板集配置
     *
     * @return
     */
    @GetMapping(value = "/editor/stencilset")
    public String getStencilset() {
        String stencilset = "";
        InputStream stencilsetStream = this.getClass().getClassLoader().getResourceAsStream("stencilset.json");
        try {
            if (null != stencilsetStream) {
                stencilset = IOUtils.toString(stencilsetStream, StandardCharsets.UTF_8.name());
            }

        } catch (Exception e) {
            throw new ActivitiException("Error while loading stencil set", e);
        }

        return stencilset;
    }

    /**
     * 获取模板编辑信息
     *
     * @param modelId
     * @return
     */
    @GetMapping(value = "/model/{modelId}/json")
    public ObjectNode getEditorJson(@PathVariable String modelId) {
        ObjectNode modelNode = null;
        Model model = repositoryService.getModel(modelId);
        if (model != null) {
            try {
                if (StringUtils.isNotEmpty(model.getMetaInfo())) {
                    modelNode = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
                } else {
                    modelNode = objectMapper.createObjectNode();
                    modelNode.put(ModelDataJsonConstants.MODEL_NAME, model.getName());
                }
                modelNode.put(ModelDataJsonConstants.MODEL_ID, model.getId());
                ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(
                        new String(repositoryService.getModelEditorSource(model.getId()), StandardCharsets.UTF_8));
                modelNode.put("model", editorJsonNode);

            } catch (Exception e) {
                log.error("Error creating model JSON", e);
                throw new ActivitiException("Error creating model JSON", e);
            }
        }
        return modelNode;
    }
}